<?php

namespace App\Handlers;


use App\Admin\Controllers\AccountController;
use App\Jobs\SynAccount;
use App\Jobs\SynDevice;
use App\Jobs\SynRebuild;
use App\Jobs\SynRedisAc;
use App\Jobs\SynRedisDe;
use App\Models\Account;
use App\Models\Addressee;
use App\Models\AdTask;
use App\Models\Device;
use App\Models\Machine;
use App\Models\MsgDevice;
use App\Models\MsgTask;
use App\Models\MsgTaskLog;
use App\Models\Task;
use Carbon\Carbon;
use Encore\Admin\Config\ConfigModel;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

class RedisHandler
{
    private $accountSetKey = "msgTask:enable-account";
    //收信人重组   ok
    public function rebuild($msg_task_id=0){
//        $msg_task_id = 0
//        $redis = app('redis');
//        $redis -> del([$this->accountSetKey]);
//        //如果是新增了任务  就这个任务重组   如果是新增收信人 就是全部任务重组
//        if($msg_task_id){
//            $msgTask = MsgTask::where($msg_task_id) -> with("sendLog") ->  get();
//        }else{
//            $msgTask = MsgTask::where("status" , "<" , 2)->where("enable",1) -> with("sendLog")-> get();
//        }
//        // 所有可用账号
//        $addressee = Addressee::where("status" , 0) -> get() -> pluck("number");
//        //如果账号不为空   就加入到redis
//        if($addressee -> isNotEmpty()){
//		$addressee =$addressee -> toArray();
//	        $redis -> sadd($this -> accountSetKey , ...$addressee);
//        }
//        //循环
//        $msgTask -> each(function (MsgTask $msgTask) use ($redis){
//            $msg_task_id = $msgTask -> id;
//            $key = "msg:app-enable-account:{$msg_task_id}";
//            $sendKey = "msg:send-log:{$msg_task_id}";
//            $redis->del([$sendKey]);
//            $sendLog = $msgTask -> sendLog -> pluck("addressee");
//            if($sendLog -> isNotEmpty()){
//                $redis -> srem($sendKey , $sendLog -> toArray());
//            }
//            $redis -> sdiffstore($key , $this -> accountSetKey , $sendKey);
//        });
        dispatch(new SynRebuild($msg_task_id));

    }
    //数据库数据到redis   ok
    static public function saveModel(Model $model, $key)
    {
        $redis = app('redis');
        $redis->del([$key]);
        $data = $model->toArray();
        foreach ($data as $v => $val)
        {
            if(is_array($val)){
                $data[$v] = json_encode($val);
            }
        }
        $redis->hmset($key, $data);
    }
    //同步消息任务    ok
    static public function syncMsgTask(MsgTask $task)
    {

        $redis = app('redis');
        $key = "dispatch:msgTask:{$task->id}";
        if (in_array($task->status, [0 , 1]) && $task->enable == 1) {
            RedisHandler::saveModel($task, $key);
        } else $redis->del([$key]);

    }
    //筛选同步消息任务  ok
    static public function syncMsgTasks()
    {
        $redis = app('redis');
        $taskKeys = $redis->keys("dispatch:msgTask:*");
        //将redis中的数据写入mysql
        foreach ($taskKeys as $taskKey) {
            $redisTask = $redis->hgetall($taskKey);
            if (!array_has($redisTask, 'id')) continue;
            $task = MsgTask::find($redisTask['id']);
            if (empty($task)) continue;
            $task->current_num = array_get($redisTask, 'current_num', 0);
            //3为已结束
            if ($task->current_num >= $task->target_num) $task->status = 3;
            $task->save();
        }
        if ($taskKeys) $redis->del($taskKeys);//清空所有redis中的任务
        //0准备1运行2取消3结束   enable 1可用 0不可用
        $tasks = MsgTask::where('status',"<" , 2) ->where('enable', 1)-> get();
        $tasks->each(function ($task) use ($redis) {
            self::syncMsgTask($task);
        });
    }
    //同步配置文件   ok
    static public function syncConfig()
    {
        $configs = ConfigModel::all();
        $configs->each(function ($config) {
            self::saveModel($config, "config:{$config->name}");
        });
    }
    //同步消息任务设备(现不用)
    static public function syncMsgDevices()
    {
        $redis = app('redis');
        $msgDeviceKeys = $redis->keys("msg:device:*");
        $msg_device_active_expire = config('msg_device_active_expire');
        foreach ($msgDeviceKeys as $msgDeviceKey) {
            $redisMsgDevice = $redis->hgetall($msgDeviceKey);
            if (!array_has($redisMsgDevice, 'id')) {
                $msgDevice = new MsgDevice();
                $msgDevice->name = $redisMsgDevice['name'];
                $msgDevice->version = $redisMsgDevice['version'];
            } else {
                $msgDevice = MsgDevice::find($redisMsgDevice['id']);
                if (empty($msgDevice)) {
                    $redis->del([$msgDeviceKey]);
                    continue;
                };
            }
            $msgDevice->success_amount = array_get($redisMsgDevice, 'success_amount', 0);
            $msgDevice->failed_amount = array_get($redisMsgDevice, 'failed_amount', 0);
            $msgDevice->last_active_time = $redisMsgDevice['last_active_time'];
            if (time() - strtotime($msgDevice->last_active_time) <= $msg_device_active_expire * 60) {
                $msgDevice->status = 1;
            }
            else {
                $msgDevice->status = 2;
                Machine::where("machine",$msgDevice->name)->delete();
            }
            $msgDevice->save();
        }
        if ($msgDeviceKeys) $redis->del($msgDeviceKeys);
        $msgDevices = MsgDevice::all();
        $msgDevices->each(function ($msgDevice) {
            self::saveModel($msgDevice, "app:device:{$msgDevice->name}");
        });
    }
    //设备状态
    static public function device()
    {
        $msg_device_names = MsgTaskLog::select([
            \DB::raw("distinct msg_device_name"),
            "msg_device_version"
        ])
            ->where('created_at', '>=', date('Y-m-d H:i:s', time() - 60 * 5))
            ->get()
            ->pluck('msg_device_version', 'msg_device_name');
        $msg_device_names->each(function ($msg_device_version, $msg_device_name) {
            MsgDevice::updateOrInsert(["name" => $msg_device_name], ['status' => TASK_STATUS_RUNNING, 'version' => $msg_device_version]);
        });
        $devices = MsgDevice::get();
        $devices->each(function (MsgDevice $device) {
            $device->success_amount =  MsgTaskLog::where('msg_device_name', $device->name)
                ->where('created_at', '>=', date('Y-m-d'))
                ->where('status', 0)
                ->count();
            $device->failed_amount =  MsgTaskLog::where('msg_device_name', $device->name)
                ->where('created_at', '>=', date('Y-m-d'))
                ->where('status', '!=', 0)
                ->count();

            $device->action_num_in_five_minutes =  MsgTaskLog::where('msg_device_name', $device->name)
                ->where('created_at', '>=', date('Y-m-d H:i:s', time() - 60 * 5))
                ->count();

            //最近5分钟有活动
            if (strtotime($device->last_active_time) <= time() - 60 * 5) {
                $device->status = 2;
                Machine::where("machine",$device->name)->delete();
            } else {
                $device->status = 1;
            }
            $device->save();
        });
    }
    //新的一天设置机器工作次数为0
    static public function clearMachine()
    {
        $redis = app('redis');
        $deviceKeys = $redis->keys('msg:device:machine:*');
        if ($deviceKeys) $redis->del($deviceKeys);
    }
    //导入数据的时候更新job   ok
    static public function syncAccount()
    {
        dispatch(new SynRedisAc());

    }
    //同步设备到redis中job  OK
    static public function syncDevice()
    {
        dispatch(new SynRedisDe());
    }
    //1个小时有更改的导入到数据库job  ok
    static public function syncDemysql()
    {
        dispatch(new SynDevice());
    }
    //1个小时有更改的导入到数据库job
    static public function syncAcmysql()
    {
        dispatch(new SynAccount());
    }
    //同步任务日志(5更新一次)ok
    static public function syncMsgLog()
    {
        $redis = app('redis');
        $keys = $redis->keys("msg:log:*");
        $reference_at =Carbon::now()->subMinutes(5)->toDateTimeString();
        if($keys){
            $logg = [];
            foreach ($keys as $logs) {
                $log = $redis->hgetall($logs);
                //使用carbon类
                if($log['current_at'] >= $reference_at){
                    $data = [
                        "msg_task_id" =>$log['msg_task_id'],
                        "deviced_sn" => $log['deviced_sn'],
                        "account_email" => $log['account_email'],
                        "msg_device_name"=>$log['msg_device_name'],
                        "status" => $log['status'],
                        "addressee"=>$log['addressee'],
                        "updated_at" =>$log['current_at'],
                    ];
                    $logg[] = $data;
//                    DB::table("msg_task_log")->insert($data);
//                    MsgTaskLog::create($data);
                    $redis->del("msg:log:".$log['msg_task_id'].":".$log['addressee'].":".$log['status']);
                }
            }
            $logg = array_chunk($logg,1000);
            foreach ($logg as $item){
//            DB::table("account_copy") -> insert($item);
                DB::table("msg_task_log") -> insert($item);
            }
        }
    }
    //redis只存5000的情况下用
//    static public function syncApiAccount($len,$status)
//    {
//        $redis = app("redis");
//        $redis->pipeline(function ($pipe) use ($len , $status){
//            $accounts = Account::where("is",'=',0)->where("status","=",$status)->take(500)->get();
//            foreach ($accounts as $account){
//                $pipe -> lpush("account:list:{$account -> status}" , $account -> email);
//                $data['email'] =$account->email;
//                $data=[
//                    'email' => $account->email,
//                    'cert' => $account->cert,
//                    'password' => $account->password,
//                    'Record_at' => $account->Record_at,
//                ];
//                $pipe->hmset("msg:account:{$account->email}",$data);
//                $account->is =1;
//                $account->save();
//            }
//        });
//    }
    //redis只存5000的情况下用
//    static public function syncApiDevice($len,$status)
//    {
//        $redis = app("redis");
//        $redis->pipeline(function ($pipe) use ($len , $status){
//            $devices = Device::where("is",'',0)->where("status","=",$status) ->take(3010-$len)->get();
//            foreach ($devices as $code){
//                $pipe -> lpush("device:list:{$code -> status}:{$code -> tp}" , $code -> sn);
//                $data =[
//                    'udid' => $code->udid,
//                    'BluetoothAddress' => $code->bt,
//                    'Imei' => $code->imei,
//                    'WiFiAddress' => $code->wifu,
//                    'ecid' => $code->ecid,
//                    'ProductType' => $code->tp,
//                    'ModelNumber' => $code->nb,
//                    'RegionInfo' => $code->reg,
//                    'serial' => $code->sn,
//                    'Ethernet' => $code->Ethernet,
//                    'ICCID' => $code->ICCID,
////                'IMSI' => $code->IMSI,
////                'BasebandSerialNumber' => $code->BasebandSerialNumber,
////                'BasebandMasterKeyHash' => $code->BasebandMasterKeyHash,
////                'BasebandChipID' => $code->BasebandChipID,
////                'Record_at' => $code->Record_at,
//                ];
//                $pipe->hmset("msg:device:{$code->sn}",$data);
//                $code->is =1;
//                $code->save();
//            }
//        });
//    }
    //redis只存5000的情况下用
    //同步设备到数据库中
//    static public function syncApiDe()
//    {
//        $redis = app('redis');
//        //获取列表长度
//        $len = $redis->llen("reply:device");
//        if($len >0){
//            $reference_at =Carbon::now()->subHour(10);
//            for ($x=0; $x<=$len; $x++) {
//                //根据sn去hash表里找
//                $key = $redis->lpop("reply:device");
//                $device =$redis->hgetall("msg:device:".$key);
//                if($device['updated_at'] >= $reference_at){
//                    DB::table("device")->where("sn",$device['sn'])->update(["status"=>$device['status'],"active"=>$device['active'],"num"=>$device['num'],"Record_at"=>$device['Record_at'],"updated_at"=>$device['updated_at'],"is"=>0]);
//                }
//                $redis->del("msg:device:".$key);
//            }
//        }
//
//    }
    //redis只存5000的情况下用
    //1个小时有更改的导入到数据库
//    static public function syncApiAc()
//    {
//        $redis = app('redis');
//        $len = $redis->llen("reply:account");
//            if($len >0){
//                $reference_at =Carbon::now()->subHour(10);
//                for ($x=0; $x<=$len; $x++) {
//                    //根据sn去hash表里找
//                    $key = $redis->lpop("reply:account");
//                    $account =$redis->hgetall("msg:account:".$key);
//                    if($account['updated_at'] >= $reference_at){
//                        DB::table("account")->where("email",$account['email'])->update(["updated_at"=>$account['updated_at'],"status"=>$account['status'],"cert"=>$account['cert'],"num"=>$account['num'],"Record_at"=>$account['Record_at'],"is"=>0]);
//                    }
//                    $redis->del("msg:device:".$key);
//                }
//            }
//    }
    //10分钟同步一下(5分钟有回执的,从hash里取出，没有回执的加入到列表0)
    //10分钟没有设备回执的继续加入到列表中ok
    //5分钟没有回执的加入原列表  不管有没有回执都同步数据库
    static public function syncOld(){
        $redis = app('redis');
        $keys = $redis->keys("old:device:*");
        $data = [];
        if($keys){
            $reference_at =Carbon::now()->subMinutes(10)->toDateTimeString();
            foreach ($keys as $devices) {
                //10分钟以前的时间
                $device = $redis->hgetall($devices);
                //如果放到集合中的时间小于5分钟以前
                if(isset($device['now_time']) && $device['now_time'] <= $reference_at){
                    $hash = $redis ->hgetall("msg:device:".$device['sn']);
                    $data[] = $hash;
                    //回到新的队列
                    if($hash['updated_at']< $device['now_time']){
                        if(!$device['status']){
                            $device['status'] =0;
                        }
                        $key = "device:list:{$device['status']}:{$device['tp']}";
                        $redis->rpush($key,$device['sn']);
                    }
                    $redis->del("old:device:".$device['sn']);

                }
            }
            $data = array_chunk($data,2000);
            foreach ($data as $datums){
                foreach($datums as $datum){
                    if(empty($datum['updated_at'])){
                        file_put_contents('update.txt' , var_export($datum['sn'], true),FILE_APPEND);
                    }
                    if(isset($datum['sn']) && !empty($datum['updated_at'])){
                        file_put_contents('update2.txt' , var_export(1, true),FILE_APPEND);

                        DB::table("device")->where("sn",$datum['sn'])->update(["updated_at" =>$datum['updated_at'],"num"=>$datum['num'],"Record_at"=>$datum['Record_at'],"updated_at"=>$datum['updated_at']]);
                    }
                }
            }
        }
    }
    //10分钟没有账号回执的继续加入到列表中
    static public function syncAcOld(){
        $time =time();
        $redis = app('redis');
        $keys = $redis->keys("old:account:*");
        $data = [];
        if($keys){
            $reference_at =Carbon::now()->subMinutes(10)->toDateTimeString();
            foreach ($keys as $accounts) {
                //10分钟以前的时间
                $account = $redis->hgetall($accounts);
                if(isset($account['now_time']) && $account['now_time'] <= $reference_at){
                    $hash = $redis ->hgetall("msg:account:".$account['email']);
                    $data[] = $hash;
                    //回到新的队列
                    if($hash['updated_at']< $account['now_time']){
                        if(!$account['status']){
                            $account['status'] =0;
                        }
                        $key = "account:list:{$account['status']}";
                        $redis->rpush($key,$account['email']);
                    }
                    $redis->del("old:account:".$account['email']);

                }
            }
            $data = array_chunk($data,2000);
            foreach ($data as $datums) {
                foreach($datums as $datum) {
                    if(isset($datum['email'])&& !empty($datum['updated_at'])){
                        DB::table("account")->where("email", $datum['email'])->update(["updated_at" =>$datum['updated_at'],"status" => $datum['status'], "cert" => $datum['cert'], "num" => $datum['num'], "Record_at" => $datum['Record_at']]);
                    }
                }
            }
        }

    }
    //定时删除已删除任务的收信人redis
    static public function taskdelete()
    {

        $redis =app("redis");
        $msgtask =DB::table("msg_task")->whereNotNull("deleted_at")->get();
        foreach ($msgtask as $task){
            if(empty($task->file_column)){
                $key ="msg:app-enable-account:".$task->id;
                if($key){
                    $keys = $redis->smembers($key);
                    $keys = array_chunk($keys, 2000);
                    $redis->pipeline(function ($pipe) use ($keys,$key){
                        foreach ($keys as $k){
                            $pipe->srem($key,...$k);
                        }
                    });
                }
            }else{
                //列表
                $v ="msg:txt:".$task->id;
                $redis->del($v);
            }
        }

    }
}
